package com.xyy.saas.payment.service.job.impl;

import com.alibaba.fastjson.JSONObject;
import com.jcraft.jsch.*;
import com.xyy.saas.payment.dao.mapper.PrePayOrderMapper;
import com.xyy.saas.payment.dao.model.FbankPayRecords;
import com.xyy.saas.payment.dao.model.PayResultOrder;
import com.xyy.saas.payment.dao.model.PrePayOrder;
import com.xyy.saas.payment.exception.PaymentException;
import com.xyy.saas.payment.pojo.vo.FBankPayRecordsVo;
import com.xyy.saas.payment.service.FbankPayRecordsService;
import com.xyy.saas.payment.service.PayResultOrderService;
import com.xyy.saas.payment.service.job.FBankSFTPManage;
import com.xyy.saas.payment.util.AmountCastUtil;
import com.xyy.saas.payment.util.ApolloUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Objects;

/**
 * https://blog.csdn.net/aoutlaw/article/details/103559886
 * 1、交易
 */
@Slf4j
@Component
public class ChannelSftpService2 {
    @Resource
    private FbankPayRecordsService fbankPayRecordsService;
    @Resource
    private PayResultOrderService payResultOrderService;
    @Resource
    private PrePayOrderMapper prePayOrderMapper;

    /**
     * 下载文件
     *
     * @param file     SFTP服务器上的文件名
     * @return         输入流
     */
    public void download(String merchantNo, String file) throws PaymentException {
        log.info("ChannelSftpService2#download file={}", file);
        Session session = getSession(merchantNo);
        ChannelSftp sftp = getChannel(session);

        try {
            String realPath = FBankSFTPManage.dir(merchantNo, FBankSFTPManage.Type.JUHE);
            log.info("ChannelSftpService2#download realPath={}", realPath);
            sftp.cd(realPath);
            read(sftp.get(file));
        }
        catch(SftpException e) {
            log.error("文件下载异常，ERROR：" + e.getMessage(), e);
            throw new PaymentException("文件下载异常");
        }
        finally {
            close(sftp, session);
        }
    }

    /**
     * 读取数据
     * @param in
     */
    private void read(InputStream in) {
        BufferedReader br = null;

        try {
            if(in != null) {
                br = new BufferedReader(new InputStreamReader(in));
                String data = null;

                while ((data = br.readLine()) != null) {
                    if(Boolean.parseBoolean(ApolloUtil.getProperty("fban_pay_records_download_debug", "false"))) {
                        log.info(data);
                    }

                    FbankPayRecords fbankPayRecords = FBankPayRecordsVo.parse2(data);

                    if(fbankPayRecords == null) {
                        log.error("ChannelSftpService#download data parse error, data={}", data);
                        continue;
                    }

                    if(!FBankPayRecordsVo.PAY_WX_MINI.equals(fbankPayRecords.getTradeType()) &&
                            !FBankPayRecordsVo.PAY_WX_PUB.equals(fbankPayRecords.getTradeType()) &&
                            !FBankPayRecordsVo.PAY_ALI.equals(fbankPayRecords.getTradeType()))
                    {
                        log.error("ChannelSftpService#download ignore trade type, data={}", data);
                        continue;
                    }

                    // 校验交易记录是否存在
                    if(fbankPayRecordsService.queryByOrderNo(fbankPayRecords.getOrderNo()) != null) {
                        continue;
                    }

                    fillParams(fbankPayRecords);
                    fbankPayRecordsService.insertSelective(fbankPayRecords);
                }
            }
        }
        catch(Exception ex) {
            log.error(ex.getMessage(), ex);
        }
        finally {
            if(br != null) {
                try {
                    br.close();
                }
                catch(Exception ex) {
                    log.error(ex.getMessage(), ex);
                }
            }
        }
    }

    /**
     * 填充参数
     * 用户提现（2）
     * 退款（38）
     * 结算到虚户（40）
     * 微信支付（205）
     * 支付宝支付（103）
     * @param fbankPayRecords
     */
    private void fillParams(FbankPayRecords fbankPayRecords) {
        List<PayResultOrder> payResultOrders = payResultOrderService.selectListByPayNo(fbankPayRecords.getClientSerialNo());

        if(CollectionUtils.isEmpty(payResultOrders)) {
            log.error("ChannelSftpService#download Business Order not fount error, data={}", JSONObject.toJSONString(fbankPayRecords));
            return;
        }

        PrePayOrder prePayOrder = prePayOrderMapper.getPrePayOrderByPayNo(fbankPayRecords.getClientSerialNo());
        fbankPayRecords.setBusinessType(prePayOrder.getBusinessType());
        fbankPayRecords.setBusinessOrderType(prePayOrder.getBusinessOrderType());
        fbankPayRecords.setExtra(prePayOrder.getBusinessOrderNo());
        fbankPayRecords.setFeeAmount(AmountCastUtil.round(prePayOrder.getAmount()));

        if(Objects.equals(fbankPayRecords.getRemarks(), "wx")) {
            fbankPayRecords.setRemarks("富民微信支付");
        }
        else if(Objects.equals(fbankPayRecords.getRemarks(), "alipay")) {
            fbankPayRecords.setRemarks("富民支付宝支付");
        }
    }

    /**
     * 连接SFTP服务器
     */
    private Session getSession(String merchantNo) throws PaymentException {
        JSch jsch = new JSch();

        try {
            //采用指定的端口连接服务器
            Session session = jsch.getSession(FBankSFTPManage.username(merchantNo), FBankSFTPManage.host(merchantNo), FBankSFTPManage.port(merchantNo));
            session.setPassword(FBankSFTPManage.password(merchantNo));
            //优先使用 password 验证   注：session.connect()性能低，使用password验证可跳过gssapi认证，提升连接服务器速度
            session.setConfig("PreferredAuthentications","password");
            //设置第一次登陆的时候提示，可选值：(ask | yes | no)
            session.setConfig("StrictHostKeyChecking","no");
            session.connect();
            return session;
        }
        catch(JSchException e){
            log.error("SFTP服务器连接异常！！" + e.getMessage(), e);
        }

        throw new PaymentException("SFTP服务器连接异常");
    }

    /**
     * 创建sftp通信通道
     * @param session
     * @return
     */
    private ChannelSftp getChannel(Session session)  throws PaymentException {
        try {
            Channel channel = session.openChannel("sftp");
            channel.connect();
            ChannelSftp sftp = (ChannelSftp) channel;
            log.info("sftp server connect success !!");
            return sftp;
        }
        catch(JSchException e) {
            log.error("SFTP服务器连接异常！！" + e.getMessage(), e);
        }

        throw new PaymentException("SFTP服务器连接异常");
    }

    /**
     * 关闭SFTP连接
     */
    private void close(ChannelSftp sftp, Session session) {
        if(sftp != null) {
            if(sftp.isConnected()) {
                sftp.disconnect();
                log.info("sftp is close already");
            }
        }

        if(session != null){
            if(session.isConnected()) {
                session.disconnect();
                log.info("session is close already");
            }
        }
    }
}